package com.tdam2013.grupo07.networking;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Set;

import javax.xml.parsers.SAXParser;

import org.xml.sax.SAXException;

import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.preference.PreferenceManager;

import com.tdam2013.grupo07.conectivity.ConectividadListener;
import com.tdam2013.grupo07.conectivity.ConectividadListener.State;
import com.tdam2013.grupo07.conectivity.ConectividadListenerSingleton;
import com.tdam2013.grupo07.data.DatabaseHelperSingleton;
import com.tdam2013.grupo07.data.DatabaseManager;
import com.tdam2013.grupo07.util.Constantes;

public class ServerConectivity implements QueryMessagesEventObservable,
		RegisterUserEventObservable, SendMessageEventObservable {
	public static final int ERROR_NO_CONECTIVITY = -1;
	/* Registration */
	public static final int ERROR_USER_ALREADY_EXISTS = 5;
	public static final int ERROR_USERNAME_OR_PASSWORD_TOO_SHORT = 13;
	/* Get messages and send messages */
	public static final int ERROR_USER_DOESNT_EXIST = 11;
	public static final int ERROR_BAD_CREDENTIALS = 12;

	private Context context;
	private Set<QueryMessagesEventObserver> queryMessageObservers;
	private Set<SendMessageEventObserver> sendMessageObservers;
	private Set<RegisterUserEventObserver> registerUserObservers;

	private DatabaseManager dbm;

	public ServerConectivity(Context context) {
		this.context = context;
		queryMessageObservers = new HashSet<QueryMessagesEventObserver>();
		sendMessageObservers = new HashSet<SendMessageEventObserver>();
		registerUserObservers = new HashSet<RegisterUserEventObserver>();

		/* DatabaseManager */
		dbm = new DatabaseManager(context.getApplicationContext(),
				DatabaseHelperSingleton.getInstance(
						context.getApplicationContext()).getDatabaseHelper());
	}

	public void registerUserAsync(String username, String password) {
		ConectividadListener conectividadListener = ConectividadListenerSingleton
				.getInstance().getConectividadListener();
		if (conectividadListener.getState() == State.CONNECTED) {
			RegisterUserTask registerUserTask = new RegisterUserTask(this);
			registerUserTask.execute(username, password);
		} else {
			RegisterUserResponse response = new RegisterUserResponse();
			response.setSuccess(false);
			response.setErrorCode(ERROR_NO_CONECTIVITY);
			publishRegistrationResponse(response);
		}
	}

	public void sendMessageAsync(String sender, String password,
			String recipient, String message) {
		ConectividadListener conectividadListener = ConectividadListenerSingleton
				.getInstance().getConectividadListener();
		if (conectividadListener.getState() == State.CONNECTED) {
			SendMessageTask sendMessageTask = new SendMessageTask(this);
			sendMessageTask.execute(sender, password, recipient, message);
		} else {
			SendMessageResponse response = new SendMessageResponse();
			response.setSuccess(false);
			response.setErrorCode(ERROR_NO_CONECTIVITY);
			response.setContact(recipient);
			response.setMessage(message);
			response.setDate(Calendar.getInstance().getTimeInMillis());
			publishSendMessageResponse(response);
		}
	}

	public void queryMessagesAsync(String user, String password,
			String timestamp) {
		ConectividadListener conectividadListener = ConectividadListenerSingleton
				.getInstance().getConectividadListener();
		if (conectividadListener.getState() == State.CONNECTED) {
			QueryMessagesTask queryMessagesTask = new QueryMessagesTask(this);
			queryMessagesTask.execute(user, password, timestamp);
		} else {
			QueryMessagesResponse response = new QueryMessagesResponse();
			response.setSuccess(false);
			response.setErrorCode(ERROR_NO_CONECTIVITY);
			publishQueryMessagesResponse(response);
		}
	}

	public void publishRegistrationResponse(RegisterUserResponse response) {
		notifyRegisterUserObservers(response);
	}

	public void publishSendMessageResponse(SendMessageResponse response) {
		long messageId = saveMessage(response);
		response.setMessageId(messageId);
		notifySendMessageObservers(response);
	}

	public void publishQueryMessagesResponse(QueryMessagesResponse response) {
		notifyQueryMessagesObservers(response);
	}

	private long saveMessage(SendMessageResponse response) {
		if (response.isSuccess()) {
			// Grabar mensaje en la bd
			SharedPreferences preferences = PreferenceManager
					.getDefaultSharedPreferences(context);

			String nombreContactoExterno = response.getContact();
			String nombreContactoUsuario = preferences.getString(
					Constantes.AJUSTES_USUARIO, null);
			long fecha = response.getDate();
			Integer tipoMensaje = Constantes.BD_TIPO_MENSAJE_ENVIADO;
			String contenido = response.getMessage();// este es el CONTENIDO del
														// mensaje??
			try {
				return DatabaseHelperSingleton
						.getInstance(context)
						.getDatabaseHelper()
						.insertarMensaje(nombreContactoExterno,
								nombreContactoUsuario, fecha, tipoMensaje,
								contenido);
			} catch (Exception ex) {
			}
		}
		return -1;
	}

	@Override
	public void addSendMessageObserver(SendMessageEventObserver observer) {
		sendMessageObservers.add(observer);
	}

	@Override
	public void removeSendMessageObserver(SendMessageEventObserver observer) {
		sendMessageObservers.remove(observer);
	}

	@Override
	public void notifySendMessageObservers(SendMessageResponse response) {
		for (SendMessageEventObserver observer : sendMessageObservers) {
			observer.updateSendMessage(response);
		}
	}

	@Override
	public void addRegisterUserObserver(RegisterUserEventObserver observer) {
		registerUserObservers.add(observer);
	}

	@Override
	public void removeRegisterUserObserver(RegisterUserEventObserver observer) {
		registerUserObservers.remove(observer);
	}

	@Override
	public void notifyRegisterUserObservers(RegisterUserResponse response) {
		for (RegisterUserEventObserver observer : registerUserObservers) {
			observer.updateRegisterUser(response);
		}
	}

	@Override
	public void addQueryMessagesObserver(QueryMessagesEventObserver observer) {
		queryMessageObservers.add(observer);
	}

	@Override
	public void removeQueryMessagesObserver(QueryMessagesEventObserver observer) {
		queryMessageObservers.remove(observer);
	}

	@Override
	public void notifyQueryMessagesObservers(QueryMessagesResponse response) {
		for (QueryMessagesEventObserver observer : queryMessageObservers) {
			observer.updateQueryMessages(response);
		}
	}
}

class RegisterUserTask extends AsyncTask<String, Void, RegisterUserResponse> {

	private ServerConectivity serverConectivity;

	public RegisterUserTask(ServerConectivity serverConectivity) {
		this.serverConectivity = serverConectivity;
	}

	protected RegisterUserResponse doInBackground(String... userData) {

		ServerHTTPInterface serverHTTPInterface = new ServerHTTPInterface();
		String response = serverHTTPInterface.registerUser(userData[0],
				userData[1]);
		RegisterUserHandler registerUserHandler = new RegisterUserHandler();
		SAXParser parser = null;
		try {
			parser = XmlParserProvider.getParser();
			parser.parse(new ByteArrayInputStream(response.getBytes()),
					registerUserHandler);
			XmlParserProvider.releaseParser(parser);
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		RegisterUserResponse registerUserResponse = registerUserHandler
				.getRegisterUserResponse();
		if (registerUserResponse != null) {
			registerUserResponse.setUsername(userData[0]);
			registerUserResponse.setPassword(userData[1]);
		} else {
			registerUserResponse = new RegisterUserResponse();
			registerUserResponse.setSuccess(false);
			registerUserResponse.setErrorCode(-2);
		}

		return registerUserResponse;
	}

	protected void onPostExecute(RegisterUserResponse response) {
		if (response == null) {
			response = new RegisterUserResponse();
			response.setSuccess(false);
		}
		serverConectivity.publishRegistrationResponse(response);
	}
}

class SendMessageTask extends AsyncTask<String, Void, SendMessageResponse> {

	private ServerConectivity serverConectivity;

	public SendMessageTask(ServerConectivity serverConectivity) {
		this.serverConectivity = serverConectivity;
	}

	protected SendMessageResponse doInBackground(String... userData) {
		ServerHTTPInterface serverHTTPInterface = new ServerHTTPInterface();
		String response = serverHTTPInterface.sendMessage(userData[0],
				userData[1], userData[2], userData[3]);
		SendMessageHandler sendMessageHandler = new SendMessageHandler();
		SAXParser parser = null;
		try {
			parser = XmlParserProvider.getParser();

			parser.parse(new ByteArrayInputStream(response.getBytes()),
					sendMessageHandler);
			XmlParserProvider.releaseParser(parser);
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		SendMessageResponse sendMessageResponse;
		sendMessageResponse = sendMessageHandler.getResponse();

		if (sendMessageResponse != null) {
			sendMessageResponse.setContact(userData[2]);
			sendMessageResponse.setMessage(userData[3]);
			sendMessageResponse.setDate(Calendar.getInstance()
					.getTimeInMillis());
		} else {
			sendMessageResponse = new SendMessageResponse();
			sendMessageResponse.setSuccess(false);
			sendMessageResponse.setErrorCode(-2);
		}
		return sendMessageResponse;
	}

	protected void onPostExecute(SendMessageResponse response) {
		if (response == null) {
			response = new SendMessageResponse();
			response.setSuccess(false);
		}

		serverConectivity.publishSendMessageResponse(response);

	}
}

class QueryMessagesTask extends AsyncTask<String, Void, QueryMessagesResponse> {

	private ServerConectivity serverConectivity;

	public QueryMessagesTask(ServerConectivity serverConectivity) {
		this.serverConectivity = serverConectivity;
	}

	protected QueryMessagesResponse doInBackground(String... userData) {
		ServerHTTPInterface serverHTTPInterface = new ServerHTTPInterface();
		String response = serverHTTPInterface.queryMessages(userData[0],
				userData[1], userData[2]);
		QueryMessagesHandler queryMessagesHandler = new QueryMessagesHandler();
		SAXParser parser = null;
		try {
			parser = XmlParserProvider.getParser();
			parser.parse(new ByteArrayInputStream(response.getBytes()),
					queryMessagesHandler);
			XmlParserProvider.releaseParser(parser);
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		QueryMessagesResponse queryMessagesResponse;

		queryMessagesResponse = queryMessagesHandler.getResponse();
		if (queryMessagesResponse == null) {
			queryMessagesResponse = new QueryMessagesResponse();
			queryMessagesResponse.setSuccess(false);
			queryMessagesResponse.setErrorCode(-2);
		}
		queryMessagesResponse.setUser(userData[0]);
		return queryMessagesResponse;
	}

	protected void onPostExecute(QueryMessagesResponse response) {
		if (response == null) {
			response = new QueryMessagesResponse();
			response.setSuccess(false);
		}

		serverConectivity.publishQueryMessagesResponse(response);

	}
}
